package edu.udo.sopra10.chaturaji.ai;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Random;

import edu.udo.sopra10.chaturaji.controllers.GameController;
import edu.udo.sopra10.chaturaji.entities.Player;
import edu.udo.sopra10.chaturaji.entities.coordinates.Position;
import edu.udo.sopra10.chaturaji.entities.pieces.Boat;
import edu.udo.sopra10.chaturaji.entities.pieces.Elephant;
import edu.udo.sopra10.chaturaji.entities.pieces.Horse;
import edu.udo.sopra10.chaturaji.entities.pieces.King;
import edu.udo.sopra10.chaturaji.entities.pieces.Pawn;
import edu.udo.sopra10.chaturaji.entities.pieces.Piece;
import edu.udo.sopra10.chaturaji.entities.pieces.Piece.Actions;
import edu.udo.sopra10.chaturaji.entities.transfer.DiceRoll;
import edu.udo.sopra10.chaturaji.entities.transfer.TransferGame;
import edu.udo.sopra10.chaturaji.events.BoardResetEvent;
import edu.udo.sopra10.chaturaji.events.MoveRequestEvent;
import edu.udo.sopra10.chaturaji.events.TurnRequestEvent;
import edu.udo.sopra10.chaturaji.exceptions.NoPieceException;

public class EasyAI extends AbstractAI {

	/**
	 * 
	 */
	private Random generator = new Random();

	public EasyAI() {
		GameController.addMoveRequestEventListener(this);
		GameController.addBoardResetEventListener(this);
		GameController.addMoveEventListener(this);
		GameController.addTurnRequestEventListener(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.udo.sopra10.chaturaji.ai.AbstractAI#getCaptureMove(edu.udo.sopra10
	 * .chaturaji.entities.pieces.Piece)
	 */
	@Override
	protected Position getCaptureMove(Piece piece) {
		Actions act = piece.getPossibleActions();

		Collection<Position> pos = act.getPossibleCaptures();

		if (pos.isEmpty()) {
			return null;
		} else {
			return (Position) pos.toArray()[0];
		}
	}

	/**
	 * Returns a random piece, if the AI has to decide between pawns and king.
	 * 
	 * @return a random piece for the move.
	 * @throws NoPieceException
	 */
	private Piece getRandomPiece() throws NoPieceException {
		LinkedList<Piece> randomPieces = new LinkedList<Piece>();
		for (Piece item : pieces) {
			if (item instanceof Pawn && getRandomPosition( item ) != null)
				randomPieces.add(item);
			if (item instanceof King && getRandomPosition( item ) != null)
				randomPieces.add(item);
		}
		if (randomPieces.isEmpty())
			throw new NoPieceException();
		for (Piece item : randomPieces) {
			if (getCaptureMove(item) != null)
				return item;
		}
		return randomPieces.get(generator.nextInt(randomPieces.size()));
	}

	/**
	 * @param piece
	 * @return a random position.
	 */
	private Position getRandomPosition(Piece piece) {
		LinkedList<Position> pos = new LinkedList<Position>(piece
				.getPossibleActions().getPossibleMoves());

		if ( pos.isEmpty() )
			return null;
		return pos.get(generator.nextInt(pos.size()));
	}

	/**
	* Makes one move for the ai player.
	*
	* @param dice
	*/
	protected boolean makeMove(DiceRoll.EquivalenceClass dice) {
		try {
			Piece piece = null;
			Position capturePosition = null;
			Position randomPosition = null;
			pieces = new LinkedList<Piece>(player.getPieces());
			switch (dice) {
			case ONE_OR_FIVE:
				piece = getRandomPiece();
				capturePosition = getCaptureMove(piece);
				randomPosition = getRandomPosition(piece);
				break;
			case TWO:
				piece = getPiece(Boat.class);
				capturePosition = getCaptureMove(piece);
				randomPosition = getRandomPosition(piece);
				break;
			case THREE:
				piece = getPiece(Horse.class);
				capturePosition = getCaptureMove(piece);
				randomPosition = getRandomPosition(piece);
				break;
			case FOUR_OR_SIX:
				piece = getPiece(Elephant.class);
				capturePosition = getCaptureMove(piece);
				randomPosition = getRandomPosition(piece);
				break;
			}
			if(randomPosition == null)return false;
			if (capturePosition == null)
				GameController.move(piece.getSquare().getPosition(),
						getRandomPosition(piece));
			else {
				GameController.move(piece.getSquare().getPosition(),
						capturePosition);
				capturePosition = null;
			}
			return true;
		} catch (NoPieceException e) {
			return false;
		}
	}

	@Override
	public void onMoveRequestEvent(MoveRequestEvent event) {
		if(event.getPlayerType() == Player.Type.AI_EASY){
			player = game.getPlayers().get(event.getPlayerId());
			ArrayList<Byte> dices = event.getUnassignedRolls();
			if(!dices.isEmpty()){
				if ( !makeMove(DiceRoll.equivalenceClassFromRoll(dices.get(0))) )
					if(dices.size() == 2){
						if( !makeMove(DiceRoll.equivalenceClassFromRoll(dices.get(1))) )
							GameController.pass();
					} else GameController.pass();
			}
		}		
	}

	@Override
	public void onTurnRequestEvent(TurnRequestEvent event) {
		if(event.getPlayerType() == Player.Type.AI_EASY){
			player = game.getPlayers().get(event.getPlayerId());
			GameController.roll();
		}		
	}

	@Override
	public void onBoardResetEvent(BoardResetEvent event) {
		game = new TransferGame( GameController.getGame() );		
	}
}
